/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.l4.app.cv;

/**
 *
 * @author Thusira
 */
import com.googlecode.javacpp.Loader;
import static com.googlecode.javacv.cpp.opencv_core.*;
import static com.googlecode.javacv.cpp.opencv_highgui.*;
import static com.googlecode.javacv.cpp.opencv_imgproc.*;
import com.googlecode.javacv.FrameGrabber.Exception;
import com.googlecode.javacv.OpenCVFrameGrabber;
import com.googlecode.javacv.cpp.opencv_core.*;
import com.l4.app.main.PointExtractor;
import com.l4.app.main.Timer;
import com.l4.app.ui.Graphs;
import com.l4.app.ui.LogPanel;
import com.l4.app.ui.TrafficLight;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.logging.Level;
import java.util.logging.Logger;

public class MotionDetect implements Runnable {

    public static double sceneArea;
    int x1, y1, x2, y2;
    private volatile boolean pauseWork = false;
    private volatile String state = "New";
    private Thread workerThread;
    public static List<Double> list;
    public static Map<Integer, Double> resultsMap;
    public static List<Integer> passList;
    public static List<Double> passValueList;
    IplImage colorImage;
    IplImage ROIFrame;

    @Override
    public void run() {
        boolean workDone = false;
        while (!workDone) {
            while (pauseWork) {
                setState("Paused");
                try {
                    Thread.sleep(5000); //stop for 100ms increments
                } catch (InterruptedException ie) {
                    //report or ignore
                }
            }
            setState("Running");
            try {
                start1();
            } catch (Exception ex) {
                Logger.getLogger(MotionDetect.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        setState("Finished");
    }

    public void pause() {
        this.pauseWork = true;
    }

    public void resume() {
        this.pauseWork = false;
        if (workerThread != null) {
            workerThread.interrupt(); //wakeup if sleeping
        }
    }

    public void stop() {
        workerThread.stop();
        System.out.println(list);
        resultsMap = new TreeMap<Integer, Double>();
        for (int i = 0; i < list.size(); i++) {
            resultsMap.put((i + 1) * 5, list.get(i));
        }
        List<Integer> keys = new ArrayList<Integer>(resultsMap.keySet());
        //Collections.sort(keys);
        for (Integer key : keys) {
            System.out.println(key + "=== " + resultsMap.get(key));
        }
//        for (Map.Entry<Integer, Double> entry : resultsMap.entrySet()) {
//            Integer key = entry.getKey();
//            Double value = entry.getValue();
//            System.out.println(key + "=" + value);
//        }
        new Graphs("XY Series Demo", list, 5).getGraph().setVisible(true);
        Map<Integer, Double> points = PointExtractor.getChangingTimings(resultsMap, Graphs.averageDensity);
        passList = new ArrayList<Integer>();
        passValueList = new ArrayList<Double>();

        for (Map.Entry<Integer, Double> entry : points.entrySet()) {
            passList.add(entry.getKey());
            passValueList.add(entry.getValue());
        }

        LogPanel logPanel = new LogPanel(passList,passValueList);
        //logPanel.setBounds(50, 50, 500,500);
        logPanel.setVisible(true);




    }

    private void setState(String state) {
        this.state = state;
    }

    public String getState() {
        return this.state;
    }

    /** startImmediately = true to begin work right away, false = start Work in paused state, call resume() to do work */
    public void start(boolean startImmediately) {
        this.pauseWork = !startImmediately;
        workerThread = new Thread(this);
        workerThread.start();
    }

    public MotionDetect(int x1, int y1, int x2, int y2) {
        this.x1 = x1;
        this.y1 = y1;
        this.x2 = x2;
        this.y2 = y2;
    }

    public void start1() throws Exception {
        list = new ArrayList<Double>();
        //FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(new File("D:/pool.avi"));
        OpenCVFrameGrabber grabber = new OpenCVFrameGrabber("D:/5.mp4");
//        final CanvasFrame canvas = new CanvasFrame("My Image");
//        canvas.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);
        grabber.start();
        IplImage frame = grabber.grab();
        CvSize imgsize = cvGetSize(frame);
        IplImage grayImage = cvCreateImage(imgsize, IPL_DEPTH_8U, 1);
        ROIFrame = cvCreateImage(cvSize((x2 - x1), (y2 - y1)), IPL_DEPTH_8U, 1);
        System.out.println("Total area---" + (x2 - x1) * (y2 - y1));

        IplImage movingAvg = cvCreateImage(imgsize, IPL_DEPTH_32F, 3);
        IplImage difference = null;
        IplImage temp = null;
        IplImage motionHistory = cvCreateImage(imgsize, IPL_DEPTH_8U, 3);
        CvRect bndRect = cvRect(0, 0, 0, 0);
        CvPoint pt1 = new CvPoint(), pt2 = new CvPoint();
        CvFont font = null;

        //Capture the movie frame by frame.
        int prevX = 0;
        int numPeople = 0;
        char[] wow = new char[65];
        int avgX = 0;

        //Indicates whether this is the first time in the loop of frames.
        boolean first = true;

        //Indicates the contour which was closest to the left boundary before the object
        //entered the region between the buildings.
        int closestToLeft = 0;
        //Same as above, but for the right.
        int closestToRight = 320;
        int frame_no = 0;

        while (true) {
            sceneArea = 0;
            colorImage = grabber.grab();
            frame_no++;

            if (colorImage != null) {
                if (first) {
                    difference = cvCloneImage(colorImage);
                    temp = cvCloneImage(colorImage);
                    cvConvertScale(colorImage, movingAvg, 1.0, 0.0);
                    first = false;
                } //else, make a running average of the motion.
                else {
                    cvRunningAvg(colorImage, movingAvg, 0.020, null);
                }

                //Convert the scale of the moving average.
                cvConvertScale(movingAvg, temp, 1.0, 0.0);

                //Minus the current frame from the moving average.
                cvAbsDiff(colorImage, temp, difference);

                //Convert the image to grayscale.
                cvCvtColor(difference, grayImage, CV_RGB2GRAY);
                //canvas.showImage(grayImage);
                //Convert the image to black and white.
                cvThreshold(grayImage, grayImage, 70, 255, CV_THRESH_BINARY);

                //Dilate and erode to get people blobs
                cvDilate(grayImage, grayImage, null, 18);
                cvErode(grayImage, grayImage, null, 5);



                cvRectangle(colorImage, /* the dest image */
                        cvPoint(x1, y1), /* top left point */
                        cvPoint(x2, y2), /* bottom right point */
                        cvScalar(255, 0, 0, 0), /* the color; blue */
                        1, 8, 0);
                cvShowImage("Original Frame", colorImage);

                if (frame_no % 50 == 0) {
                    ROIFrame = cvCloneImage(grayImage);
                    cvSetImageROI(ROIFrame, cvRect(x1, y1, (x2 - x1), (y2 - y1)));
                    cvShowImage("ROI Frame", ROIFrame);
                    CvMemStorage storage = cvCreateMemStorage(0);
                    CvSeq contour = new CvSeq(null);
                    int val = cvFindContours(ROIFrame, storage, contour, Loader.sizeof(CvContour.class), CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);
                    System.out.println("=====frame id======" + frame_no);
                    System.out.println("=====conturs======" + val);
                    while (contour != null && !contour.isNull()) {
                        double add = Math.abs(cvContourArea(contour, CV_WHOLE_SEQ, 0));
                        bndRect = cvBoundingRect(contour, 0);
                        pt1.x(bndRect.x());
                        pt1.y(bndRect.y());
                        pt2.x(bndRect.x() + bndRect.width());
                        pt2.y(bndRect.y() + bndRect.height());

                        ////Get an average X position of the moving contour.
                        avgX = (pt1.x() + pt2.x()) / 2;

                        if (avgX > 250 && avgX < 500) {
                            //If the the previous contour was within 2 of the left boundary...
                            if (closestToLeft >= 88 && closestToLeft <= 90) {
                                //If the current X position is greater than the previous...
                                if (avgX > prevX) {
                                    //Increase the number of people.
                                    numPeople++;

                                    //Reset the closest object to the left indicator.
                                    closestToLeft = 0;
                                }
                            } //else if the previous contour was within 2 of the right boundary...
                            else if (closestToRight >= 250 && closestToRight <= 252) {
                                //If the current X position is less than the previous...
                                if (avgX < prevX) {
                                    //Increase the number of people.
                                    numPeople++;

                                    //Reset the closest object to the right counter.
                                    closestToRight = 320;
                                }
                            }

                            //Draw the bounding rectangle around the moving object.
                            cvRectangle(ROIFrame, pt1, pt2, CV_RGB(200, 0, 200), 1, 8, 0);
                        }
                        // end contour if

                        //If the current object is closer to the left boundary but still not across
                        //it, then change the closest to the left counter to this value.
                        if (avgX > closestToLeft && avgX <= 90) {
                            closestToLeft = avgX;
                        }

                        //If the current object is closer to the right boundary but still not across
                        //it, then change the closest to the right counter to this value.
                        if (avgX < closestToRight && avgX >= 250) {
                            closestToRight = avgX;
                        }

                        //Save the current X value to use as the previous in the next iteration.
                        prevX = avgX;
                        System.out.println(numPeople);
                        sceneArea = sceneArea + add;
                        contour = contour.h_next();
                    }
                    System.out.println("++++++++++" + sceneArea);
                    System.out.println("######################################################");
                    list.add((sceneArea / ((x2 - x1) * (y2 - y1))) * 100);

                }


                //Wait for the user to see it.
                cvWaitKey(10);

            }
        }

    }
}
//    public static void main(String args[]) throws Exception, InterruptedException {
//        new Timer().start();
//        List<Double> list=new ArrayList<Double>();
//        //FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(new File("D:/pool.avi"));
//        OpenCVFrameGrabber grabber = new OpenCVFrameGrabber("D:/2.avi");
//        final CanvasFrame canvas = new CanvasFrame("My Image");
//        canvas.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);
//        grabber.start();
//        IplImage frame = grabber.grab();
//        CvSize imgsize = cvGetSize(frame);
//        IplImage grayImage = cvCreateImage(imgsize, IPL_DEPTH_8U, 1);
//        IplImage ROIFrame = cvCreateImage(cvSize((265 - 72), (214 - 148)), IPL_DEPTH_8U, 1);
//        IplImage colorImage;
//        IplImage movingAvg = cvCreateImage(imgsize, IPL_DEPTH_32F, 3);
//        IplImage difference = null;
//        IplImage temp = null;
//        IplImage motionHistory = cvCreateImage(imgsize, IPL_DEPTH_8U, 3);
//
//
//        CvRect bndRect = cvRect(0, 0, 0, 0);
//        CvPoint pt1 = new CvPoint(), pt2 = new CvPoint();
//        CvFont font = null;
//
//        //Capture the movie frame by frame.
//        int prevX = 0;
//        int numPeople = 0;
//        char[] wow = new char[65];
//
//        int avgX = 0;
//
//        //Indicates whether this is the first time in the loop of frames.
//        boolean first = true;
//
//        //Indicates the contour which was closest to the left boundary before the object
//        //entered the region between the buildings.
//        int closestToLeft = 0;
//        //Same as above, but for the right.
//        int closestToRight = 320;
//        int frame_no = 0;
//
//
//
//        while (true) {
//            sceneArea = 0;
//            colorImage = grabber.grab();
//            frame_no++;
//
//            if (colorImage != null) {
//                if (first) {
//                    difference = cvCloneImage(colorImage);
//                    temp = cvCloneImage(colorImage);
//                    cvConvertScale(colorImage, movingAvg, 1.0, 0.0);
//                    first = false;
//                    //cvShowImage("My Window1", difference);
//                } //else, make a running average of the motion.
//                else {
//                    cvRunningAvg(colorImage, movingAvg, 0.020, null);
//                }
//
//                //Convert the scale of the moving average.
//                cvConvertScale(movingAvg, temp, 1.0, 0.0);
//
//                //Minus the current frame from the moving average.
//                cvAbsDiff(colorImage, temp, difference);
//
//                //Convert the image to grayscale.
//                cvCvtColor(difference, grayImage, CV_RGB2GRAY);
//                //canvas.showImage(grayImage);
//                //Convert the image to black and white.
//                cvThreshold(grayImage, grayImage, 70, 255, CV_THRESH_BINARY);
//
//                //Dilate and erode to get people blobs
//                cvDilate(grayImage, grayImage, null, 18);
//                cvErode(grayImage, grayImage, null, 10);
//                canvas.showImage(colorImage);
//
//                if (frame_no % 8 == 0) {
//                    ROIFrame = cvCloneImage(grayImage);
//                    cvSetImageROI(ROIFrame, cvRect(72, 148, (265 - 72), (214 - 148)));
//                    //cvOr(outFrame, tempFrame, outFrame);
//                    cvShowImage("ROI Frame", ROIFrame);
//
//
//
//                    cvRectangle(colorImage, /* the dest image */
//                            cvPoint(72, 148), /* top left point */
//                            cvPoint(265, 214), /* bottom right point */
//                            cvScalar(255, 0, 0, 0), /* the color; blue */
//                            1, 8, 0);
//
//                    CvMemStorage storage = cvCreateMemStorage(0);
//                    CvSeq contour = new CvSeq(null);
//                    int val = cvFindContours(ROIFrame, storage, contour, Loader.sizeof(CvContour.class), CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);
//
////                System.out.println("ROI frame area:" + (265 - 72) * (214 - 148));
//
//                    //CvSeq curr_contour = contour;
//
////                while (contour != null) {
////                    double area = cvContourArea(contour, CV_WHOLE_SEQ, 0);
////                    System.out.println("====C===="+area);
////                    contour = contour.h_next();
////                }
//
//
//                    System.out.println("=====frame id======" + frame_no);
//                    System.out.println("=====conturs======" + val);
//                    while (contour != null && !contour.isNull()) {
////                    CvRect rect = cvBoundingRect(contour, 0);
////                    cvRectangle(colorImage, cvPoint(rect.x(), rect.y() + rect.height()), cvPoint(rect.x() + rect.width(), rect.y()), CV_RGB(200, 0, 200), 1, 8, 0);
////                    double area = cvContourArea(contour, CV_WHOLE_SEQ, 0);
//
//                        double add = Math.abs(cvContourArea(contour, CV_WHOLE_SEQ, 0));
//
//                        bndRect = cvBoundingRect(contour, 0);
//
//                        pt1.x(bndRect.x());
//                        pt1.y(bndRect.y());
//                        pt2.x(bndRect.x() + bndRect.width());
//                        pt2.y(bndRect.y() + bndRect.height());
//
//                        ////Get an average X position of the moving contour.
//                        avgX = (pt1.x() + pt2.x()) / 2;
//
//                        ////If the contour is within the edges of the building...
//                        if (avgX > 250 && avgX < 500) {
//                            //If the the previous contour was within 2 of the left boundary...
//                            if (closestToLeft >= 88 && closestToLeft <= 90) {
//                                //If the current X position is greater than the previous...
//                                if (avgX > prevX) {
//                                    //Increase the number of people.
//                                    numPeople++;
//
//                                    //Reset the closest object to the left indicator.
//                                    closestToLeft = 0;
//                                }
//                            } //else if the previous contour was within 2 of the right boundary...
//                            else if (closestToRight >= 250 && closestToRight <= 252) {
//                                //If the current X position is less than the previous...
//                                if (avgX < prevX) {
//                                    //Increase the number of people.
//                                    numPeople++;
//
//                                    //Reset the closest object to the right counter.
//                                    closestToRight = 320;
//                                }
//                            }
//
//                            //Draw the bounding rectangle around the moving object.
//                            cvRectangle(ROIFrame, pt1, pt2, CV_RGB(200, 0, 200), 1, 8, 0);
//                        }
//                        // end contour if
//
//                        //If the current object is closer to the left boundary but still not across
//                        //it, then change the closest to the left counter to this value.
//                        if (avgX > closestToLeft && avgX <= 90) {
//                            closestToLeft = avgX;
//                        }
//
//                        //If the current object is closer to the right boundary but still not across
//                        //it, then change the closest to the right counter to this value.
//                        if (avgX < closestToRight && avgX >= 250) {
//                            closestToRight = avgX;
//                        }
//
//                        //Save the current X value to use as the previous in the next iteration.
//                        prevX = avgX;
//
//                        System.out.println(numPeople);
//
//                        sceneArea = sceneArea + add;
//
//                        contour = contour.h_next();
//                    }
//
//                    System.out.println("++++++++++" + sceneArea);
//                    list.add(sceneArea);
//                }
//
//
//
//
////                if (contour.elem_size() > 0) {
////                    CvSeq points = cvApproxPoly(contour, Loader.sizeof(CvContour.class),
////                            storage, CV_POLY_APPROX_DP, cvContourPerimeter(contour)*0.02, 0);
////                    cvDrawContours(grabbedImage, points, CvScalar.BLUE, CvScalar.BLUE, -1, 1, CV_AA);
////                }
//
//
//                //Write the number of people counted at the top of the output frame.
//                //cvInitFont(font, CV_FONT_HERSHEY_SIMPLEX, 0.8, 0.8, 0, 2);
//                //cvInitFont(font, CV_FONT_HERSHEY_SIMPLEX, 0.8, 0.8, 0, 2, 2);
//                //cvPutText(colorImage, Integer.toString(numPeople), cvPoint(60, 200), font, cvScalar(0, 0, 0, 300));
//
//                //Show the frame.
////                cvShowImage("My Window", colorImage);
//
//                //Wait for the user to see it.
//                cvWaitKey(10);
//
//            }
//
//            //If this is the first time, initialize the images.
//            //Thread.sleep(50);
//        }
//
//    }
//}
////
////        IplImage image = cvLoadImage(sourcePath);
////        IplImage grayImage = cvCreateImage(cvGetSize(image), IPL_DEPTH_8U, 1);
////        cvCvtColor(image, grayImage, CV_BGR2GRAY);
////
////        CvMemStorage mem;
////        CvSeq contours = new CvSeq();
////        CvSeq ptr = new CvSeq();
////        cvThreshold(grayImage, grayImage, 150, 255, CV_THRESH_BINARY);
////        mem = cvCreateMemStorage(0);
////
////        cvFindContours(grayImage, mem, contours, sizeof(CvContour.class) , CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0));
////
////        Random rand = new Random();
////        for (ptr = contours; ptr != null; ptr = ptr.h_next()) {
////            Color randomColor = new Color(rand.nextFloat(), rand.nextFloat(), rand.nextFloat());
////            CvScalar color = CV_RGB( randomColor.getRed(), randomColor.getGreen(), randomColor.getBlue());
////            cvDrawContours(image, ptr, color, CV_RGB(0,0,0), -1, CV_FILLED, 8, cvPoint(0,0));
////        }
////        cvSaveImage(targetPath, image);
//

